package com.chenxin.wms.process.inbound.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.chenxin.common.annotation.WmsLogs;
import com.chenxin.common.core.domain.ProcResult;
import com.chenxin.common.enums.WmsSpuStatus;
import com.chenxin.common.enums.wms.*;
import com.chenxin.common.exception.wms.WmsException;
import com.chenxin.common.utils.StringUtils;
import com.chenxin.wms.domain.IbDetailEntity;
import com.chenxin.wms.domain.IbMasterEntity;
import com.chenxin.wms.domain.StockEntity;
import com.chenxin.wms.domain.TaskEntity;
import com.chenxin.wms.domain.dto.WipMaterialRegisterParams;
import com.chenxin.wms.domain.po.SpuInfo;
import com.chenxin.wms.domain.po.StationInfo;
import com.chenxin.wms.mapper.*;
import com.chenxin.wms.process.inbound.IProcIbMasterStatusUpdate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;

@Service
public class ProcWipMaterialRegister implements com.chenxin.wms.process.inbound.IProcWipMaterialRegister {
    @Autowired
    private IbMasterMapper ibMasterMapper;
    @Autowired
    private IbDetailMapper ibDetailMapper;
    @Autowired
    private SpuMapper spuMapper;
    @Autowired
    private StationMapper stationMapper;
    @Autowired
    private StockMapper stockMapper;
    @Autowired
    private TaskMapper taskMapper;
    @Autowired
    private IProcIbMasterStatusUpdate procIbMasterStatusUpdate;

    @Transactional
    @WmsLogs(name = "原材收货登记")
    @Override
    public ProcResult call(WipMaterialRegisterParams dto) {
        if (dto == null) {
            return ProcResult.error("wip_register_000", "请求参数不能为空");
        }
        // 0.获取相关参数
        Long ibDetailId = dto.getIbDetailId();
        String stationNo = dto.getStationNo();
        String contNo = dto.getContNo();
        String reelId = dto.getReelId();
        String lotNo = dto.getLotNo();
        BigDecimal inQty = dto.getInQty();
        Long creator = dto.getCreator();
        // 创建时间
        Date workDate = new Date();
        // 1.参数校验
        ProcResult validResult = validateParameters(ibDetailId, stationNo, contNo, inQty);
        if (!validResult.getCode().equals("0")) {
            return validResult;
        }
        // 2.根据明细ID获取入库单明细信息
        IbDetailEntity detailInfo = ibDetailMapper.selectById(ibDetailId);
        if (detailInfo == null) {
            return ProcResult.error("wip_register_005", "入库明细ID【" + ibDetailId + "】不存在");
        }
        // 获取主单的单据信息
        IbMasterEntity ibMaster = ibMasterMapper.selectById(detailInfo.getIbMasterId());
        if (ibMaster == null) {
            return ProcResult.error("wip_register_006", "入库主单ID【" + detailInfo.getIbMasterId() + "】不存在");
        }
        //2.1 根据入库明细单查询主单信息是原材料入库单
        if (ibMaster.getIbMasterType() == null || !ibMaster.getIbMasterType().equals(MasterType.PO_IN_WIP.getCode())) {
            return ProcResult.error("wip_register_006", "非原料入库单【PO_IN_WIP】，无法进行原料收货登记！明细ID【" + ibDetailId + "】");
        }
        // 3.根据明细信息获取其他所需信息
        String spuNo = detailInfo.getSpuNo();
        int ibDetailStatus = detailInfo.getIbDetailStatus();
        // 3.1.1.判断物料是否维护，是否在保质期（暂不考虑）
        SpuInfo spuInfo = spuMapper.selectSpuInfoByNo(spuNo);
        if (spuInfo == null) {
            return ProcResult.error("wip_register_006", "物料【" + spuNo + "】不存在，明细ID【" + ibDetailId + "】");
        }
        if (StringUtils.isEmpty(String.valueOf(spuInfo.getWarehouseId()))) {
            return ProcResult.error("wip_register_006", "物料【" + spuNo + "】未配置默认仓库，明细ID【" + ibDetailId + "】");
        }
        if (StringUtils.isEmpty(String.valueOf(spuInfo.getZoneId()))) {
            return ProcResult.error("wip_register_006", "物料【" + spuNo + "】未配置默认上架区域，明细ID【" + ibDetailId + "】");
        }
        // 3.1.废弃物料或者未维护物料不允许收货
        if (spuInfo.getDelFlag().equals(WmsSpuStatus.DELETE.getCode()) || String.valueOf(spuInfo.getSpuStatus()).equals(WmsSpuStatus.DISABLE.getCode())) {
            return ProcResult.error("wip_register_007", "物料【" + spuNo + "】已停用或废弃，不允许收货，明细ID【" + ibDetailId + "】");
        }
        // 3.2.判断明细单据状态是否允许继续收货状态
        if (ibDetailStatus > IbDetailStatus.EXEC.getCode()) {
            return ProcResult.error("wip_register_008", "明细ID【" + ibDetailId + "】当前状态【" + ibDetailStatus + "】不允许收货");
        }
        // 3.3判断收货数量是否大于入库单明细剩余数量（计划-实际）
        BigDecimal remainQty = detailInfo.getIbPlanQty().subtract(detailInfo.getIbActualQty());
        if (inQty.compareTo(remainQty) > 0) {
            return ProcResult.error("wip_register_009", "当前收货数量【" + inQty + "】大于可收货数量【" + remainQty + "】，不允许收货，明细ID【" + ibDetailId + "】");
        }
        // 4.根据收货站台获取库区信息
        StationInfo stationInfo = stationMapper.selectStationInfoByNo(stationNo);
        if (stationInfo == null) {
            return ProcResult.error("wip_register_009", "当前站台【" + stationNo + "】未维护，不允许进行收货！明细ID【" + ibDetailId + "】");
        }
        String zoneType = stationInfo.getZoneType();
        String stationType = stationInfo.getStationType();
        // 收货登记的位置（任务的起始位置）
        String fromPosition = stationInfo.getLocationNo();
        if (StringUtils.isEmpty(fromPosition)) {
            return ProcResult.error("wip_register_012", "当前站台【" + stationNo + "】未配置对应的货位信息，明细ID【" + ibDetailId + "】");
        }
        // 收货登记暂不入库（任务的目的地）
        String toPosition = "";
        // 4.1判断站台是否可用且为入库站台
        if (!StationType.SI.getCode().equals(stationType)) {
            return ProcResult.error("wip_register_010", "当前站台【" + stationNo + "】不是收货站台，明细ID【" + ibDetailId + "】");
        }
        // 4.2.判断物料的默认上架库区与站台所属库区是否一致,不一致不允许收货
        if (!Objects.equals(spuInfo.getZoneId(), stationInfo.getZoneId())) {
            return ProcResult.error("wip_register_011", "物料【" + spuNo + "】的默认上架库区与收货站台【" + stationNo + "】所属库区不一致，明细ID【" + ibDetailId + "】");
        }

        // 7.1.查询当前容器的所有库存（同一个LPN无法在多个站台进行收货登记）
        QueryWrapper<StockEntity> stockQW = new QueryWrapper<>();
        stockQW.lambda().eq(StockEntity::getContNo, contNo);
        List<StockEntity> existsStocks = stockMapper.selectList(stockQW);

        // 7.2.检查容器混载情况（只检查，不合并）
        if (existsStocks != null && existsStocks.size() > 0) {
            for (StockEntity stock : existsStocks) {
                // 检查所有库存的所在位置是否与当前收货位置一致
                if (!fromPosition.equals(stock.getLocationNo())) {
                    return ProcResult.error("wip_register_016", "当前容器【" + contNo + "】已存在其他位置的库存，不能用于本次收货，明细ID【" + ibDetailId + "】");
                }
                // 不同批次的物料不能收取到同一个托盘上（混批校验）
                if (!stock.getLotNo().equals(lotNo)) {
                    return ProcResult.error("wip_register_017", "当前容器【" + contNo + "】已存在其他批次的库存，不能用于本次收货，明细ID【" + ibDetailId + "】");
                }
            }
        }

        // 8.判断LPN是否存在其他类型的任务,检查有没有出库任务
        QueryWrapper<TaskEntity> taskQW = new QueryWrapper<>();
        taskQW.lambda().eq(TaskEntity::getFromContNo, contNo)
                .lt(TaskEntity::getTaskStatus, TaskStatus.DONE.getCode());
        List<TaskEntity> existsTasks = taskMapper.selectList(taskQW);
        if (existsTasks != null && existsTasks.size() > 0) {
            for (TaskEntity task : existsTasks) {
                if (!task.getTaskSubType().equals(TaskType.SUB_GOODS_IN.getCode())) {
                    return ProcResult.error("wip_register_015", "当前容器【" + contNo + "】已存在其他场景任务，不能用于本次收货，明细ID【" + ibDetailId + "】");
                }
            }
        }

        // 9.处理库存记录 - 每次登记都创建新的库存记录
        StockEntity registerStock = new StockEntity();
        registerStock.setContNo(contNo);
        registerStock.setLocationNo(fromPosition);
        registerStock.setSpuNo(spuNo);
        registerStock.setLotNo(lotNo);
        registerStock.setStockQty(inQty);
        // 免检=合格 非免检=待检
        registerStock.setQualityStatus(spuInfo.getIsQuality().equals("0") ? StockQuality.QB.getCode() : StockQuality.QA.getCode());
        registerStock.setReelId(reelId);
        registerStock.setIbDetailId(ibDetailId);
        registerStock.setSupplierNo(ibMaster.getSupplierNo());
        registerStock.setCreator(creator);
        registerStock.setCreateDate(workDate);

        // 写入库存
        stockMapper.insert(registerStock);
        // 9.3 每次登记都创建新的任务记录
        TaskEntity registerTask = new TaskEntity();
        registerTask.setTaskType(TaskType.RECEIVE_IN.getCode());
        registerTask.setTaskSubType(TaskType.SUB_GOODS_IN.getCode());
        registerTask.setTaskStatus(TaskStatus.INIT.getCode());
        registerTask.setFromContNo(contNo);
        // 10.1存放物料信息
        registerTask.setSpuNo(spuNo);
        registerTask.setLotNo(lotNo);
        registerTask.setPlanQty(inQty);
        registerTask.setMasterNo(detailInfo.getIbMasterNo());
        registerTask.setMasterId(detailInfo.getIbMasterId());
        registerTask.setDetailId(ibDetailId);
        //10.2 货位位置信息
        registerTask.setFromPosition(fromPosition);
        registerTask.setCurPosition(fromPosition);
        registerTask.setToPosition(toPosition);
        registerTask.setStationNo(stationNo);
        // 写入关联库存ID
        registerTask.setStockId(registerStock.getStockId());
        registerTask.setCreator(creator);
        registerStock.setCreateDate(workDate);
        // 10.3写入任务
        taskMapper.insert(registerTask);

        // 11.1.判断单据是否收货完成（计划收货数量=实际收货数量）
        if (inQty.compareTo(remainQty) < 0) {
            detailInfo.setIbDetailStatus(IbDetailStatus.EXEC.getCode());
        } else {
            detailInfo.setIbDetailStatus(IbDetailStatus.DONE.getCode());
        }

        // 11.2.更新入库明细单据信息（将收货数量累加到实际数量上）
        detailInfo.setIbActualQty(detailInfo.getIbActualQty().add(inQty));
        UpdateWrapper<IbDetailEntity> detailUW = new UpdateWrapper<>();
        detailUW.lambda().set(IbDetailEntity::getIbActualQty, detailInfo.getIbActualQty())
                .set(IbDetailEntity::getIbDetailStatus, detailInfo.getIbDetailStatus())
                .set(IbDetailEntity::getLotNo, lotNo)
                .set(IbDetailEntity::getUpdater, creator)
                .set(IbDetailEntity::getUpdateDate, workDate)
                .set(IbDetailEntity::getVersion, detailInfo.getVersion() + 1)
                .eq(IbDetailEntity::getIbDetailId, ibDetailId)
                .eq(IbDetailEntity::getVersion, detailInfo.getVersion());
        int rowByUpdateDetail = ibDetailMapper.update(detailUW);
        if (rowByUpdateDetail == 0) {
            throw new WmsException("wip_register_015", "入库登记失败!更新入库明细【" + ibDetailId + "】异常");
        }

        // 11.3.更新主单状态
        //procIbMasterStatusUpdate.statusUpdateByMasterId(ibMaster.getIbMasterId(), creator);
        return ProcResult.success("收货成功，明细ID【" + ibDetailId + "】，LPN【" + contNo + "】物料【" + detailInfo.getSpuNo() + "】收货数量【" + inQty + "】，作业站台【" + stationNo + "】");
    }

    /* 参数填写校验  */
    private ProcResult validateParameters(Long ibDetailId, String stationNo, String contNo, BigDecimal inQty) {
        if (StringUtils.isNull(ibDetailId)) {
            return ProcResult.error("wip_register_001", "入库明细ID不能为空");
        }
        if (StringUtils.isNull(stationNo)) {
            return ProcResult.error("wip_register_002", "收货站台不能为空");
        }
        if (StringUtils.isNull(contNo)) {
            return ProcResult.error("wip_register_003", "LPN不能为空");
        }
        if (inQty.compareTo(BigDecimal.ZERO) <= 0) {
            return ProcResult.error("wip_register_004", "收货数量不能小于等于0");
        }
        // TODO 收货托盘是否维护
        return ProcResult.success("必填校验");
    }
}
